home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / t3_1 / nexttsrc.lha / nexttsources / sources / sys / buffer.t < prev    next >
Text File  |  1990-06-19  |  19KB  |  482 lines

  1. (herald buffer
  2.   (env tsys))
  3.  
  4. ;;; Copyright (c) 1985 Yale University
  5. ;;;     Authors: N Adams, R Kelsey, D Kranz, J Philbin, J Rees.
  6. ;;; This material was developed by the T Project at the Yale University Computer 
  7. ;;; Science Department.  Permission to copy this software, to redistribute it, 
  8. ;;; and to use it for any purpose is granted, subject to the following restric-
  9. ;;; tions and understandings.
  10. ;;; 1. Any copy made of this software must include this copyright notice in full.
  11. ;;; 2. Users of this software agree to make their best efforts (a) to return
  12. ;;;    to the T Project at Yale any improvements or extensions that they make,
  13. ;;;    so that these may be included in future releases; and (b) to inform
  14. ;;;    the T Project of noteworthy uses of this software.
  15. ;;; 3. All materials developed as a consequence of the use of this software
  16. ;;;    shall duly acknowledge such use, in accordance with the usual standards
  17. ;;;    of acknowledging credit in academic research.
  18. ;;; 4. Yale has made no warrantee or representation that the operation of
  19. ;;;    this software will be error-free, and Yale is under no obligation to
  20. ;;;    provide any services, by way of maintenance, update, or otherwise.
  21. ;;; 5. In conjunction with products arising from the use of this material,
  22. ;;;    there shall be no use of the name of the Yale University nor of any
  23. ;;;    adaptation thereof in any advertising, promotional, or sales literature
  24. ;;;    without prior written consent from Yale in each case.
  25. ;;;
  26.  
  27. ;;; (import pool structure)
  28. ;;; (import (let valid-spec?))
  29.  
  30. ;;; describe buffers
  31.  
  32. ;++ T3 plans include:
  33. ;++  buffered i/o; update mode; re-openability; seeking & telling;
  34. ;++  TCP/IP interface.
  35. ;++ Change internal names to %buffer
  36.  
  37. ;++ what should be integrated?
  38. ;++ pooled structures
  39. ;++ should these things have read-tables? probably.
  40.  
  41.  
  42.  
  43. ;;; Buffer management.
  44.  
  45. ;;; %buffer modes
  46.  
  47. ;;; Major modes
  48. (define-constant iob/closed      #x00)    ; mode field set to zero
  49. (define-constant iob/read        #x01)
  50. (define-constant iob/write       #x02)
  51. (define-constant iob/append      #x04)
  52. (define-constant iob/dump        #x08)    ;++ remove
  53. (define-constant iob/retrieve    #x10)   ;++ remove
  54. (define-constant iob/inquire     #x20)   ; used to get info about the file.
  55.  
  56. ;;; Minor modes
  57. (define-constant iob/interactive #x0100)
  58. (define-constant iob/permanent   #x0200)  ; cannot be closed
  59. (define-constant iob/socket      #x0400)  ; TCP/IP
  60. (define-constant iob/window      #x0800)  ;
  61. (define-constant iob/transcript  #x1000)  ;
  62.  
  63. ;;; Mode predicates
  64.  
  65. (define-integrable (iob-mode? mode type) (fxN= 0 (fx-and mode type)))
  66.  
  67. (define-integrable (iob-closed? iob)      (fx-zero? (iob-mode iob)))
  68. (define-integrable (iob-readable? iob)    (iob-mode? (iob-mode iob) iob/read))
  69. (define-integrable (iob-writable? iob)
  70.   (or (iob-mode? (iob-mode iob) iob/write)
  71.       (iob-mode? (iob-mode iob) iob/append)))
  72. (define-integrable (iob-append? iob)      (iob-mode? (iob-mode iob) iob/append))
  73. (define-integrable (iob-inquire? iob)     (iob-mode? (iob-mode iob) iob/inquire))
  74. (define-integrable (iob-dump? iob)        (iob-mode? (iob-mode iob) iob/dump))
  75. (define-integrable (iob-retrieve? iob)    (iob-mode? (iob-mode iob) iob/retrieve))
  76.  
  77. (define-integrable (iob-interactive? iob) (iob-mode? (iob-mode iob) iob/interactive))
  78. (define-integrable (iob-permanent? iob)   (iob-mode? (iob-mode iob) iob/permanent))
  79. (define-integrable (iob-socket? iob)      (iob-mode? (iob-mode iob) iob/socket))
  80. (define-integrable (iob-window? iob)      (iob-mode? (iob-mode iob) iob/window))
  81. (define-integrable (iob-transcript? iob)  (iob-mode? (iob-mode iob) iob/transcript))
  82.  
  83. ;;; Convert a mode or mode list to an iob-mode.
  84.  
  85. (define (mode->iob-mode caller filespec modespec)
  86.   (labels (((major mode item)
  87.             (let ((val (case item
  88.                          ((in)          iob/read)
  89.                          ((out)         iob/write)
  90.                          ((inquire)     iob/inquire)
  91.                          ((append)      iob/append)
  92.                          ((dump)        (fx-ior iob/write iob/dump))
  93.                          ((retrieve)    (fx-ior iob/read iob/retrieve))
  94.                          (else          (mode-error item)))))
  95.               (fx-ior mode val)))
  96.          ((minor mode items)
  97.           (iterate loop ((mode mode) (items items))
  98.             (if (null? items)
  99.                 mode
  100.                 (let ((val (case (car items)
  101.                              ((interactive) iob/interactive)
  102.                              ((permanent)   iob/permanent)
  103.                              ((socket)      iob/socket)
  104.                              ((window)      iob/window)
  105.                              ((transcript)  iob/transcript)
  106.                              (else          (mode-error (car items))))))
  107.                   (loop (fx-ior mode val) (cdr items))))))
  108.          ((mode-error item)
  109.           (mode->iob-mode 
  110.            caller 
  111.            filespec
  112.            (error "bad file mode ~s in - (~s ~a ~s ...)~
  113.                   ~10tType (RET mode) to retry."
  114.                   item
  115.                   caller 
  116.                   (if (iob? filespec) (iob-id filespec) filespec)
  117.                   modespec))))
  118.     (if (pair? modespec)
  119.         (minor (major 0 (car modespec)) (cdr modespec))
  120.         (major 0 modespec))))
  121.                                
  122. (define (unsupported-mode-error proc filespec mode)
  123.   (error "unsupported file mode - (~s ~a ~s ...)~
  124.           ~10tType (RET modespec) to retry."
  125.           proc 
  126.           (if (iob? filespec) (iob-id filespec) filespec)
  127.           mode))
  128.                                
  129.  
  130. ;++ write-string, read-block, force-output, newline,
  131. ;++ peek-char, port->iob, close, and re-open can be flushed from
  132. ;++ IOB.
  133.  
  134. (define-structure-type iob
  135.                        id          ; pathname
  136.                        mode        ; type of buffer
  137.                        rt          ; read-table
  138.                        buffer      ; text to hold data (bytev?)
  139.                        offset      ; current position in buffer
  140.                        limit       ; end of data in buffer
  141.                        underflow   ; underflow procedure
  142.                        overflow    ; overflow procedure
  143.                        xeno        ; system dependent descriptor
  144.                                    ; or 'buffer.
  145.                        h           ; hpos
  146.                        prev-h      ; previous hpos
  147.                        v           ; vpos
  148.                        indent
  149.                        wrap-column
  150.                        line-length          
  151.                        eof-flag?
  152.   (((read-char       (#f obj))       (vm-read-char obj))
  153.    ((write-char      (#f obj) c)     (vm-write-char obj c))
  154.    ((maybe-read-char (#f obj))       (vm-maybe-read-char obj))
  155.    ((newline         (#f obj))       (vm-newline obj))
  156.    ((unread-char     (#f obj))       (vm-unread-char obj))
  157.    ((peek-char       (#f obj))       (vm-peek-char obj))
  158.    ((write-string    (#f obj) s)     (vm-write-string obj s))
  159.    ((force-output    (#f obj))       (vm-force-output obj))
  160.    ((read-block (#f obj) extend cnt)
  161.     (vm-read-block obj extend cnt))
  162.    ((hpos            (#f obj))      (if (iob-closed? obj)
  163.                                               (closed-port-error obj)
  164.                                               (iob-h obj)))
  165.    ((vpos            (#f obj))       (if (iob-closed? obj)
  166.                                                (closed-port-error obj)
  167.                                                (iob-v obj)))
  168.    ((line-length     (#f obj))       (iob-line-length obj))
  169.    ((set-line-length (#f obj) len)   (set (iob-line-length obj) len))
  170.    ((wrap-column     (#f obj))       (iob-wrap-column obj))
  171.    ((set-wrap-column (#f obj) len)   (set (iob-wrap-column obj) len))
  172.    ((input-port?     (#f obj))       (iob-readable? obj))
  173.    ((output-port?    (#f obj))       (iob-writable? obj))
  174.    ((interactive?    (#f obj))       (iob-interactive? obj))
  175.    ((port? self)                           (ignore self) '#t)
  176.    ((port->iob       (#f obj)) obj)
  177.    ((port-read-table (#f obj))
  178.     (cond ((iob-rt obj))
  179.           (else standard-read-table)))
  180.    ((set-port-read-table (#f obj) new-read-table)
  181.     (set (iob-rt obj) new-read-table))
  182.    ((port-name (#f obj))              (iob-id obj))
  183.    ((set-port-name (#f obj) name)     (set (iob-id obj) name))
  184.    ((close           (#f obj))        (close-port obj))
  185.    ((re-open         (#f obj) mode)   (re-open-port! obj mode))
  186.    ((display         (#f obj) stream)
  187.     (iterate loop ((i 0))
  188.       (let ((buffer (iob-buffer obj)))
  189.         (cond ((fx>= i (iob-offset obj)) (no-value))
  190.               (else
  191.                (vm-write-char stream (text-elt buffer i))
  192.                (loop (fx+ i 1)))))))
  193.    ((print (#f obj) stream)
  194.     (format stream "#{Port~_~a~_~a}"
  195.                     (iob-id obj)
  196.                     (object-hash obj)))))
  197.  
  198. ;++ initialize the STYPE master.
  199.  
  200. (define standard-line-length 80)
  201. (define standard-wrap-column (fx- standard-line-length 15))
  202.  
  203. (set (iob-id          (stype-master iob-stype)) nil)
  204. (set (iob-mode        (stype-master iob-stype)) iob/closed)
  205. (set (iob-buffer      (stype-master iob-stype)) '#f)
  206. (set (iob-eof-flag?   (stype-master iob-stype)) '#f)
  207. (set (iob-h           (stype-master iob-stype)) 0)
  208. (set (iob-prev-h      (stype-master iob-stype)) 0)
  209. (set (iob-v           (stype-master iob-stype)) 0)
  210. (set (iob-indent      (stype-master iob-stype)) 0)
  211. (set (iob-wrap-column (stype-master iob-stype)) standard-wrap-column)
  212. (set (iob-line-length (stype-master iob-stype)) standard-line-length)
  213. (set (iob-rt          (stype-master iob-stype)) '#f)
  214.  
  215. (define-constant buffer?       iob?)
  216. (define-constant buffer-length iob-offset)
  217. (define-constant buffer-text   iob-buffer)
  218. (define-constant (buffer-empty? iob)
  219.   (if (fx= (iob-offset iob) 0) '#t '#f))
  220.  
  221. (define buffer-elt
  222.   (object (lambda (iob n)
  223.             (text-elt (iob-buffer iob) n))  
  224.     ((setter self)
  225.      (lambda (iob n ch)
  226.        (let ((ch (enforce char? ch)))
  227.          (set (text-elt (iob-buffer iob) n) ch))))))
  228.  
  229. (define-integrable (max-buffer-length iob)
  230.   (text-length (iob-buffer iob)))
  231.  
  232. (define (buffer-fill! iob char count)
  233.   (let ((iob  (enforce buffer? iob))
  234.         (char (enforce char?   char)))
  235.     (do ((i 0 (fx+ i 1)))
  236.         ((fx>= i count))
  237.       (vm-write-char iob char)))
  238.    (no-value))
  239.  
  240. (define (buffer->string! b)
  241.   (let ((s (make-string 0)))
  242.     (set (string-text s)   (iob-buffer b))
  243.     (set (string-length s) (buffer-length b))
  244.     s))
  245.  
  246. (define (buffer->string iob)
  247.   (let* ((len  (buffer-length iob))
  248.          (str  (make-string len))
  249.          (text (string-text str)))
  250.     (move-text (iob-buffer iob) 0 text 0 len)
  251.     str))
  252.  
  253. (define (string->input-port str)
  254.   (let* ((len  (string-length str))
  255.          (iob  (get-buffer-of-size len))
  256.          (text (iob-buffer iob)))
  257.     (do ((i 0 (fx+ i 1)))
  258.         ((fx>= i len)
  259.          (set (iob-offset iob) 0)
  260.          (set (iob-limit iob)  len)
  261.          (set (iob-mode iob) iob/read)
  262.          iob)
  263.       (set (text-elt text i) (string-elt str i)))))
  264.  
  265. ;++ Should return an update port, but for now it returns an input
  266. ;++ port.
  267.  
  268. (define string->buffer string->input-port)
  269.  
  270. ;;; Make sure that the channel hasn't been closed
  271.  
  272. (define (iob-channel iob)
  273.   (if (iob-closed? iob) (closed-port-error iob) (iob-xeno iob)))
  274.  
  275. (define (closed-port-error iob)
  276.   (non-continuable-error "~s is closed." (iob-id iob)))
  277.  
  278.  
  279. ;++ Should this be lap? or primop. This uses indexing, on a machine
  280. ;++ with tags it would use pointers into objects.
  281. ;++ move it to the appropriate file.
  282.  
  283. (define-integrable (MOVE-TEXT SRC S-OFF DST D-OFF N)
  284.   (do ((n n (fx- n 1))
  285.        (s-off s-off (fx+ s-off 1))
  286.        (d-off d-off (fx+ d-off 1)))
  287.       ((fx<= n 0) (no-value))
  288.     (set (text-elt dst d-off) (text-elt src s-off))))
  289.  
  290. ;;; Make an I/O buffer.  Used by VM before pools are available.
  291.  
  292. (define (CREATE-IOB ID CHAN MODE SIZE)
  293.   (let ((iob (make-iob)))
  294.     (set (iob-buffer iob) (make-text size))
  295.     (initialize-iob iob id chan mode)))
  296.  
  297. (define (ensure-iob-size text-pool iob size)
  298.   (cond ((not (iob-buffer iob))
  299.          (set (iob-buffer iob) (obtain-from-pool (text-pool size))))
  300.         ((fx> size (max-buffer-length iob))
  301.          (let ((text (iob-buffer iob)))
  302.            (return-to-pool (text-pool (text-length text)) text)
  303.            (set (iob-buffer iob) (obtain-from-pool (text-pool size)))))))
  304.  
  305. (define (initialize-iob iob id chan mode)
  306.   (set (iob-id          iob) id)
  307.   (set (iob-mode        iob) mode)
  308.   (set (iob-offset      iob) 0)
  309.   (set (iob-xeno        iob) chan)
  310.   (set (iob-h           iob) 0)
  311.   (set (iob-prev-h      iob) 0)
  312.   (set (iob-v           iob) 0)
  313.   (set (iob-indent      iob) 0)
  314.   (set (iob-wrap-column iob) standard-wrap-column)
  315.   (set (iob-line-length iob) standard-line-length)
  316.   (set (iob-rt          iob) '#f)
  317.   (set (iob-eof-flag?   iob) '#f)
  318.   (cond ((iob-readable? iob)
  319.          (set (iob-limit iob) 0)
  320.          (set (iob-underflow iob) %vm-read-buffer)
  321.          (set (iob-overflow iob) overflow-error))
  322.         ((or (iob-writable? iob) (iob-append? iob))
  323.          (set (iob-limit iob) (max-buffer-length iob))
  324.          (set (iob-underflow iob) underflow-error)
  325.          (set (iob-overflow iob) (lambda (iob size)
  326.                                    (ignore size)
  327.                                    (%vm-write-buffer iob)))))
  328.   iob)
  329.  
  330. (define (overflow-error buf size)
  331.   (ignore size)
  332.   (error "buffer ~a overflowed." buf))
  333.  
  334. (define (underflow-error buf block?) (ignore buf block?) eof)
  335.  
  336. ;;; There are ten pools, for buffers of various sizes.
  337. ;;;    0    1    2    3     4     5     6     7      8      9
  338. ;;;   64  128  256  512  1024  2048  4096  8192  16834  32768
  339.  
  340. ;;; Return a pool from which one can obtain a buffer whose size
  341. ;;; is >= N.
  342.  
  343. (define (make-vector-of-pools maker type? min-size max-size)
  344.   (let ((pools (make-vector 10)))
  345.     (do ((i 0 (fx+ i 1))
  346.          (n min-size (fixnum-ashl n 1)))
  347.         ((fx> i 9))
  348.       (set (vref pools i)
  349.            (make-pool `(extend-pool ,i)
  350.                       (lambda () (maker n))
  351.                       1
  352.                       type?)))
  353.     (lambda (n)
  354.       (cond ((fx<= n min-size)
  355.              (vref pools 0))  ; speed hack for common case
  356.             (else
  357.              (let ((i (fixnum-howlong (fixnum-ashr (fx- n 1) 6))))
  358.                (if (fx> n max-size)
  359.                    (error "cannot allocate buffer of size ~a~%" n)
  360.                    (vref pools i))))))))
  361.  
  362.  
  363. (define-operation (obtain pool))
  364. (define-operation (release pool))
  365. (define-operation (release-buffer-text pool buffer))
  366. (define-operation (get-i/o-buffer pool id chan mode size))
  367.  
  368. ;;; Note: OVERFLOW below is a bit complicated and gross.  It makes
  369. ;;;       sure that the IOB can hold at least N additional characters.
  370. ;;;       If not the buffers size is increased by allocating a buffer
  371. ;;;       of the appropriate size, copying the contents of the old
  372. ;;;       buffer to the new, and finally exchanging the text pointers
  373. ;;;       of the two buffers creating a transparent side effect.
  374.  
  375. (define (make-buffer-pool)
  376.   (let* ((iob-pool  (make-pool 'buffer-pool make-iob 1 iob?))
  377.          (text-pool (make-vector-of-pools  make-text
  378.                                            text?
  379.                                            min-iob-size
  380.                                            max-iob-size))
  381.          (rel-text  (lambda (text)
  382.                       (return-to-pool
  383.                         (text-pool (text-length text)) text)))
  384.          (underflow (lambda (iob #f) (end-of-file iob)))
  385.          (overflow  (lambda (iob n)
  386.                       (let* ((old-size (text-length (iob-buffer iob)))
  387.                              (temp (obtain-from-pool
  388.                                     (text-pool (fx+ old-size n)))))
  389.                         (move-text (iob-buffer iob) 0 temp 0 old-size)
  390.                         (exchange (iob-buffer iob) temp)
  391.                         (return-to-pool (text-pool old-size) temp))
  392.                       (set (iob-limit iob) (max-buffer-length iob))
  393.                       (no-value)))
  394.          (get-buffer (lambda (mode size)
  395.                        (let ((iob  (obtain-from-pool iob-pool))
  396.                              (text (obtain-from-pool (text-pool size))))
  397.                          (set (iob-buffer iob) text)
  398.                          (init-buffer iob mode underflow overflow)))))
  399.     (object (lambda (mode size)
  400.               (get-buffer mode size))
  401.       ((obtain self)
  402.        (get-buffer iob/write 0))
  403.       ((release self obj)
  404.        (let* ((iob  (enforce iob? obj))
  405.               (text (iob-buffer iob)))
  406.          (set (iob-buffer iob) '#f)
  407.          (set (iob-id     iob) '#f)
  408.          (set (iob-xeno   iob) '#f)
  409.          (if text (rel-text text))
  410.          (return-to-pool iob-pool iob)))
  411.       ((release-buffer-text self obj)
  412.        (let ((iob (enforce iob? obj)))
  413.          (let ((text (iob-buffer iob)))
  414.            (set (iob-buffer iob) '#f)
  415.            (rel-text text))))
  416.       ((get-i/o-buffer self file chan mode size)
  417.        (receive (iob id)
  418.                 (if (iob? file)
  419.                     (return file (iob-id file))
  420.                     (return (obtain-from-pool iob-pool) file))
  421.          (ensure-iob-size text-pool iob size)
  422.          (initialize-iob iob id chan mode)))
  423.       ((pool-statistics self stream)
  424.        (pool-statistics iob-pool stream))
  425.       ((print-type-string self) "Buffer pool"))))
  426.  
  427. ;;; Initialize an ephemeral buffer
  428.  
  429. (define (init-buffer buf mode underflow overflow)
  430.   (set (iob-mode        buf) mode)
  431.   (set (iob-offset      buf) 0)
  432.   (set (iob-h           buf) 0)
  433.   (set (iob-prev-h      buf) 0)
  434.   (set (iob-v           buf) 0)
  435.   (set (iob-indent      buf) 0)
  436.   (set (iob-wrap-column buf) standard-wrap-column)
  437.   (set (iob-line-length buf) standard-line-length)
  438.   (set (iob-rt          buf) '#f)
  439.   (set (iob-eof-flag?   buf) '#f)
  440.   (cond ((iob-readable? buf)
  441.          (set (iob-limit     buf) 0)
  442.          (set (iob-underflow buf) underflow)
  443.          (set (iob-overflow  buf) overflow-error))
  444.         ((iob-writable? buf)
  445.          (set (iob-limit     buf) (max-buffer-length buf))
  446.          (set (iob-underflow buf) underflow-error)
  447.          (set (iob-overflow  buf) overflow)))
  448.   buf)
  449.  
  450. ;;; T's internal buffers.  There used for real and ephemeral I/O.
  451. ;;; This stuff will eventually be eliminated and the higher level
  452. ;;; stuff above will replace it.
  453.  
  454. (define-constant min-iob-size 64)
  455. (define-constant max-iob-size 32768)
  456.  
  457. (define %buffer-pool (make-buffer-pool))
  458.  
  459. ;;; Obtain a small buffer.
  460.  
  461. (define-integrable (GET-BUFFER)
  462.   (%buffer-pool iob/write 0))
  463.  
  464. ;;; Obtain a buffer whose size is >= N.
  465.  
  466. (define-integrable (GET-BUFFER-OF-SIZE SIZE)
  467.   (let ((size (enforce fixnum? size)))
  468.     (%buffer-pool iob/write size)))
  469.  
  470. ;;; Release an iob.
  471.  
  472. (define-integrable (RELEASE-BUFFER iob)
  473.   (release %buffer-pool iob))
  474.  
  475. ;;; a portable interface to buffered i/o
  476.  
  477. (define (channel->port channel name modespec buffer-size)
  478.   (let* ((mode (mode->iob-mode 'channel->port name modespec))
  479.          (iob (get-i/o-buffer %buffer-pool name channel mode buffer-size)))
  480. ;++ (set (table-entry open-port-table iob) (object-hash iob))
  481.     iob))
  482.